<template>
	<div class="monitor-service-dashboard-container">
		<el-row>
			<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb15">
				<el-card shadow="hover">
					<el-descriptions style="overflow-x: auto;" title="应用基本参数" :column="3" border>
						<el-descriptions-item>
							<template v-slot:label>应用健康状态</template>
							<span class="color-success" v-if="appinfo.status == 'UP'">{{appinfo.status}} 正常</span>
							<span class="color-danger" v-else>{{appinfo.status}} 异常</span>
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>CPU核心数</template>
							<span class="color-primary">{{appinfo.cpuCount}}</span>
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>应用启动耗时</template>
							<span class="color-primary">{{appinfo.startedTime}}</span> ms
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>应用准备耗时</template>
							<span class="color-primary">{{appinfo.readyTime}}</span> ms
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>应用已运行时间</template>
							<span class="color-primary">{{appinfo.uptime}}</span> s
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>应用启动时间点</template>
							{{appinfo.startTime}}
						</el-descriptions-item>
					</el-descriptions>
				</el-card>
			</el-col>
		</el-row>
		<el-row>
			<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb15">
				<el-card shadow="hover">
					<el-descriptions style="overflow-x: auto;" title="JVM基本参数" :column="3" border>
						<el-descriptions-item>
							<template v-slot:label>缓冲区总数</template>
							<span class="color-primary">{{jvminfo.bufferCount}}</span>
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>GC总次数</template>
							<span class="color-primary">{{jvminfo.gcPauseCount}}</span>
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>GC总耗时</template>
							<span class="color-primary">{{jvminfo.gcPauseTotalTime}}</span> s
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>缓冲区已用内存</template>
							<span class="color-primary">{{jvminfo.bufferMemoryUsed}}</span> MB
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>缓冲区总容量</template>
							<span class="color-primary">{{jvminfo.bufferTotalCapacity}}</span> MB
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>FullGC老年代内存空间</template>
							<span class="color-primary">{{jvminfo.gcLiveDataSize}}</span> MB
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>GC老年代最大内存空间</template>
							<span class="color-primary">{{jvminfo.gcMaxDataSize}}</span> MB
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>GC年轻代分配内存空间</template>
							<span class="color-primary">{{jvminfo.gcMemoryAllocated}}</span> MB
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>GC老年代分配内存空间</template>
							<span class="color-primary">{{jvminfo.gcMemoryPromoted}}</span> MB
						</el-descriptions-item>
					</el-descriptions>
				</el-card>
			</el-col>
		</el-row>
		<el-row>
			<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" class="mb15">
				<el-card shadow="hover" header="磁盘消耗情况">
					<div style="height: 300px" ref="diskSpaceRef"></div>
				</el-card>
			</el-col>
			<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" class="mb15">
				<el-card shadow="hover" header="内存使用情况">
					<div style="height: 300px" ref="memorySpaceRef"></div>
				</el-card>
			</el-col>
		</el-row>
		<el-row>
			<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb15">
				<el-card shadow="hover" header="内存使用率">
					<div style="height: 300px" ref="memoryUsedRef"></div>
				</el-card>
			</el-col>
		</el-row>
		<el-row>
			<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb15">
				<el-card shadow="hover" header="CPU使用率">
					<div style="height: 300px" ref="cpuUsageRef"></div>
				</el-card>
			</el-col>
		</el-row>
		<el-row>
			<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb15">
				<el-card shadow="hover" header="线程统计情况">
					<div style="height: 300px" ref="threadInfoRef"></div>
				</el-card>
			</el-col>
		</el-row>
	</div>
</template>

<script lang="ts">
import { ref, toRefs, reactive, onMounted, onBeforeUnmount, nextTick, onActivated, watch } from 'vue';
import { useRoute } from 'vue-router';
import * as echarts from 'echarts';
import { storeToRefs } from 'pinia';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { formatDate } from '/@/utils/formatTime';
import { getServiceDisk, getServiceCpu, getServiceMemory, getServiceAppInfo, getServiceJvmInfo, getServiceThreadInfo } from '/@/api/monitor/service/index';
interface DashboardState {
	eventSource: any,
	myCharts: any[],
	hashKey: string,
	appinfo: any,
	jvminfo: any,
	jvm: {
		memory: {
			max: number,
		}
	},
	tableData: {
		data: any[],
		total: number,
		loading: boolean
	}
}
export default {
	name: 'service/dashboard',
	components: { },
	setup() {
		const diskSpaceRef = ref();
		const cpuUsageRef = ref();
		const memorySpaceRef = ref();
		const memoryUsedRef = ref();
		const threadInfoRef = ref();
		const route = useRoute();
		const storesTagsViewRoutes = useTagsViewRoutes();
		const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
		const state = reactive<DashboardState>({
			eventSource: {},
			myCharts: [],
			hashKey: '',
			appinfo: {},
			jvminfo: {},
			jvm: {
				memory: {
					max: 0,
				}
			},
			tableData: {
				data: [],
				total: 0,
				loading: false
			}
		});
		
		const initAppInfo = () => {
			getServiceAppInfo({hashKey : state.hashKey}).then(res => {
				if(res.code == 0){
					state.appinfo = res.data;
				}
			})
		}
		
		const initJvmInfo = () => {
			getServiceJvmInfo({hashKey : state.hashKey}).then(res => {
				if(res.code == 0){
					state.jvminfo = res.data;
				}
			})
		}

		const initDiskSpaceChart = () => {
			const myChart = echarts.init(diskSpaceRef.value);
			state.myCharts.push(myChart);
			const loadOptions = () => {
				getServiceDisk({hashKey : state.hashKey}).then((res) => {
					if(res.code == 0){
						const options = {
							series: [{
								type: 'gauge',
								radius: '100%',
								max: Math.ceil(res.data.total),
								splitNumber: 10,
								axisLine: {
									lineStyle: {
										width: 30,
										color: [
											[0.3, '#67e0e3'],
											[0.7, '#37a2da'],
											[1, '#fd666d']
										]
									}
								},
								pointer: {
									itemStyle: {
										color: 'auto'
									}
								},
								axisTick: {
									distance: -30,
									length: 8,
									lineStyle: {
										color: '#fff',
										width: 2
									}
								},
								splitLine: {
									distance: -30,
									length: 30,
									lineStyle: {
										color: '#fff',
										width: 4
									}
								},
								axisLabel: {
									color: 'auto',
									distance: 40,
									fontSize: 10
								},
								detail: {
									valueAnimation: true,
									formatter: '{value} GB',
									color: 'auto',
									fontSize: 20
								},
								data: [{
									value: (res.data.total - res.data.free).toFixed(2),
								}]
							}]
						};
						myChart.setOption(options);
					}
				});
			}
			loadOptions();
		}
		
		const initThreadInfoChart = () => {
			const myChart = echarts.init(threadInfoRef.value);
			state.myCharts.push(myChart);
			const options = {
				grid: {
					top: 30,
					right: 30,
					bottom: 30,
					left: 50,
				},
				tooltip: {
					trigger: 'item',
					formatter: '{c}',
					axisPointer: {
						type: 'cross'
					}
				},
				legend: {
					data: ['线程总数', '活动线程数', '守护线程数'],
					right: 0,
				},
				xAxis: {
					type: 'category',
					boundaryGap: false,
					data: []
				},
				yAxis: {
					type: 'value',
					axisLabel: {
						formatter: '{value}'
					},
				},
				series: [{
					name: '线程总数',
					data: [],
					type: 'line',
					smooth: true,
					lineStyle: { color: '#67c23a' },
					itemStyle: { color: '#67c23a', borderColor: '#67c23a' },
					areaStyle: {
						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
							{ offset: 0, color: '#67c23ab3' },
							{ offset: 1, color: '#67c23a03' },
						]),
					},
				},
				{
					name: '活动线程数',
					data: [],
					type: 'line',
					smooth: true,
					lineStyle: { color: '#9E87FF' },
					itemStyle: { color: '#9E87FF', borderColor: '#9E87FF' },
					areaStyle: {
						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
							{ offset: 0, color: '#9E87FFb3' },
							{ offset: 1, color: '#9E87FF03' },
						]),
					},
				},
				{
					name: '守护线程数',
					data: [],
					type: 'line',
					smooth: true,
					lineStyle: { color: '#fe9a8b' },
					itemStyle: { color: '#fe9a8b', borderColor: '#fe9a8b' },
					areaStyle: {
						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
							{ offset: 0, color: '#fe9a8bb3' },
							{ offset: 1, color: '#fe9a8b03' },
						]),
					},
				}]
			}
			if(window.EventSource){
				state.eventSource.thread = getServiceThreadInfo({hashKey : state.hashKey});
				state.eventSource.thread.addEventListener('open', () => {
					console.info('SSE连接成功');
				});
				state.eventSource.thread.addEventListener('message', (e) => {
					try {
						const res = JSON.parse(e.data);
						if(res.code == 0){
							let time = formatDate(new Date(), 'mm:ss');
							options.xAxis.data.push(time);
							options.series[0].data.push(res.data.states);
							options.series[1].data.push(res.data.live);
							options.series[2].data.push(res.data.daemon);
							if(options.xAxis.data.length > 30){
								options.xAxis.data.shift();
								options.series[0].data.shift();
								options.series[1].data.shift();
								options.series[2].data.shift();
							}
							myChart.setOption(options);
						}
					} catch (error) {
						console.log(error);
					}
				});
				state.eventSource.thread.addEventListener('error', (e) => {
					if (e.readyState === EventSource.CLOSED) {
						console.log('SSE连接关闭');
					} else {
						console.log(e);
					}
				})
			}else{
				ElMessage.warning('您的浏览器不支持SSE');
			}
		}
		
		const initCpuUsageChart = () => {
			const myChart = echarts.init(cpuUsageRef.value);
			state.myCharts.push(myChart);
			const options = {
				grid: {
					top: 30,
					right: 30,
					bottom: 30,
					left: 50,
				},
				tooltip: {
					trigger: 'item',
					formatter: '{c} %',
					axisPointer: {
						type: 'cross'
					}
				},
				legend: {
					data: ['进程CPU使用率', '系统CPU使用率'],
					right: 0,
				},
				xAxis: {
					type: 'category',
					boundaryGap: false,
					data: []
				},
				yAxis: {
					type: 'value',
					axisLabel: {
						formatter: '{value} %'
					},
				},
				series: [{
					name: '进程CPU使用率',
					data: [],
					type: 'line',
					smooth: true,
					lineStyle: { color: '#67c23a' },
					itemStyle: { color: '#67c23a', borderColor: '#67c23a' },
					areaStyle: {
						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
							{ offset: 0, color: '#67c23ab3' },
							{ offset: 1, color: '#67c23a03' },
						]),
					},
				},
				{
					name: '系统CPU使用率',
					data: [],
					type: 'line',
					smooth: true,
					lineStyle: { color: '#9E87FF' },
					itemStyle: { color: '#9E87FF', borderColor: '#9E87FF' },
					areaStyle: {
						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
							{ offset: 0, color: '#9E87FFb3' },
							{ offset: 1, color: '#9E87FF03' },
						]),
					},
				}]
			}
			if(window.EventSource){
				state.eventSource.cpu = getServiceCpu({hashKey : state.hashKey});
				state.eventSource.cpu.addEventListener('open', () => {
					console.info('SSE连接成功');
				});
				state.eventSource.cpu.addEventListener('message', (e) => {
					try {
						const res = JSON.parse(e.data);
						if(res.code == 0){
							let time = formatDate(new Date(), 'mm:ss');
							options.xAxis.data.push(time);
							options.series[0].data.push((res.data.process * 100).toFixed(2));
							options.series[1].data.push((res.data.system * 100).toFixed(2));
							if(options.xAxis.data.length > 30){
								options.xAxis.data.shift();
								options.series[0].data.shift();
								options.series[1].data.shift();
							}
							myChart.setOption(options);
						}
					} catch (error) {
						console.log(error);
					}
				});
				state.eventSource.cpu.addEventListener('error', (e) => {
					if (e.readyState === EventSource.CLOSED) {
						console.log('SSE连接关闭');
					} else {
						console.log(e);
					}
				})
			}else{
				ElMessage.warning('您的浏览器不支持SSE');
			}
		}
		
		const initMemoryUsedChart = () => {
			const myChart = echarts.init(memoryUsedRef.value);
			state.myCharts.push(myChart);
			const options = {
				grid: {
					top: 10,
					right: 30,
					bottom: 30,
					left: 50,
				},
				tooltip: {
					trigger: 'item',
					formatter: '{c} %',
					axisPointer: {
						type: 'cross'
					}
				},
				xAxis: {
					type: 'category',
					boundaryGap: false,
					data: []
				},
				yAxis: {
					type: 'value',
					axisLabel: {
						formatter: '{value} %'
					}
				},
				series: [{
					data: [],
					type: 'line',
					smooth: true,
					lineStyle: { color: '#67c23a' },
					itemStyle: { color: '#67c23a', borderColor: '#67c23a' },
					areaStyle: {
						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
							{ offset: 0, color: '#67c23ab3' },
							{ offset: 1, color: '#67c23a03' },
						]),
					},
				}]
			}

			const myChart2 = echarts.init(memorySpaceRef.value);
			state.myCharts.push(myChart2);
			const options2 = {
				series: [{
					type: 'gauge',
					radius: '100%',
					max: 100,
					splitNumber: 10,
					axisLine: {
						lineStyle: {
							width: 30,
							color: [
								[0.3, '#67e0e3'],
								[0.7, '#37a2da'],
								[1, '#fd666d']
							]
						}
					},
					pointer: {
						itemStyle: {
							color: 'auto'
						}
					},
					axisTick: {
						distance: -30,
						length: 8,
						lineStyle: {
							color: '#fff',
							width: 2
						}
					},
					splitLine: {
						distance: -30,
						length: 30,
						lineStyle: {
							color: '#fff',
							width: 4
						}
					},
					axisLabel: {
						color: 'auto',
						distance: 40,
						fontSize: 10
					},
					detail: {
						valueAnimation: true,
						formatter: '{value} MB',
						color: 'auto',
						fontSize: 20
					},
					data: [{
						value: 0.00,
					}]
				}]
			};
			myChart2.setOption(options2);

			if(window.EventSource){
				state.eventSource.memory = getServiceMemory({hashKey : state.hashKey});
				state.eventSource.memory.addEventListener('open', () => {
					console.info('SSE连接成功');
				});
				state.eventSource.memory.addEventListener('message', (e) => {
					try {
						const res = JSON.parse(e.data);
						if(res.code == 0){
							state.jvm.memory.max = res.data.max;
							let time = formatDate(new Date(), 'mm:ss');
							options.xAxis.data.push(time);
							options.series[0].data.push((res.data.usage * 100).toFixed(2));
							if(options.xAxis.data.length > 30){
								options.xAxis.data.shift();
								options.series[0].data.shift();
							}
							myChart.setOption(options);

							options2.series[0].max = Math.ceil(res.data.max);
							options2.series[0].data[0].value = res.data.used.toFixed(2);
							myChart2.setOption(options2);
						}
					} catch (error) {
						console.log(error);
					}
				});
				state.eventSource.memory.addEventListener('error', (e) => {
					if (e.readyState === EventSource.CLOSED) {
						console.log('SSE连接关闭');
					} else {
						console.log(e);
					}
				})
			}else{
				ElMessage.warning('您的浏览器不支持SSE');
			}
		}

		// 页面加载时
		onMounted(() => {
			state.hashKey = route.query.hashKey as string;
			initAppInfo();
			initJvmInfo();
			initDiskSpaceChart();
			initThreadInfoChart();
			initCpuUsageChart();
			initMemoryUsedChart();
			initEchartsResize();
		});
		
		onBeforeUnmount(() => {
			if(state.eventSource.cpu){
				state.eventSource.cpu.close();
			}
			if(state.eventSource.memory){
				state.eventSource.memory.close();
			}
			if(state.eventSource.thread){
				state.eventSource.thread.close();
			}
		})
		
		// 批量设置 echarts resize
		const initEchartsResizeFun = () => {
			nextTick(() => {
				for (let i = 0; i < state.myCharts.length; i++) {
					state.myCharts[i].resize();
				}
			});
		};
		// 批量设置 echarts resize
		const initEchartsResize = () => {
			window.addEventListener('resize', initEchartsResizeFun);
		};
		// 由于页面缓存原因，keep-alive
		onActivated(() => {
			initEchartsResizeFun();
		});
		// 监听 vuex 中的 tagsview 开启全屏变化，重新 resize 图表，防止不出现/大小不变等
		watch(
			() => isTagsViewCurrenFull.value,
			() => {
				initEchartsResizeFun();
			}
		);
		
		return {
			diskSpaceRef,
			threadInfoRef,
			cpuUsageRef,
			memorySpaceRef,
			memoryUsedRef,
			...toRefs(state),
		};
	},
};
</script>